package com.txtsqlclient.ui.si;

import java.sql.Connection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.txtsqlclient.dataaccess.DAOException;
import com.txtsqlclient.dataaccess.database.QueryExecutionDAO;
import com.txtsqlclient.dataaccess.database.connection.ConnectionException;
import com.txtsqlclient.dataaccess.database.connection.ConnectionFactory;
import com.txtsqlclient.domain.QueryExecutionException;
import com.txtsqlclient.domain.QueryResult;
import com.txtsqlclient.domain.ReadQueryResult;
import com.txtsqlclient.domain.WriteQueryResult;
import com.txtsqlclient.ui.exception.SubInterfaceException;
import com.txtsqlclient.ui.helper.TabularLayoutHelper;
import com.txtsqlclient.ui.vo.Session;

/**
 * @author spadda
 * 
 */
public class QuerySubInterface extends NoPromptBasedSubInterface {

	protected QueryResult queryResult;

	private static int MAX_WIDTH = 170;

	private final static Log LOGGER = LogFactory
			.getLog(QuerySubInterface.class);

	protected ConnectionFactory getConnectionFactory() {
		return ConnectionFactory.getInstance();
	}

	protected QueryExecutionDAO getQueryExecutionDAO() {
		return QueryExecutionDAO.getInstance();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.txtsqlclient.ui.InputHandler#handleInput(com.txtsqlclient.ui.Session)
	 */
	public void handleInput(final Session session) throws SubInterfaceException {
		try {
			validateQuery();
			LOGGER.trace("Query validation complete.");
			executeQuery(session);
			LOGGER.trace("Query execution complete.");
			showResults();
			LOGGER.trace("Query output rendering complete");
		} catch (ConnectionException ce) {
			throw new SubInterfaceException(
					"Error while establishing connection", ce);
		} catch (QueryExecutionException qe) {
			throw new SubInterfaceException(
					"There was an error executing the query", qe);
		}
	}

	protected void executeQuery(final Session session)
			throws QueryExecutionException, ConnectionException {
		QueryExecutionDAO dao = getQueryExecutionDAO();
		ConnectionFactory factory = getConnectionFactory();
		try {
			Connection con = factory.getConnection(session);
			this.queryResult = dao.execute(session.getCommand(), con);
		} catch (DAOException de) {
			throw new QueryExecutionException("Error while executing query", de);
		}
	}

	// TODO Ideally, there should be two Query Sub interfaces, 'Read' and
	// 'Write', based on these conditions. These sub interfaces should just have
	// the showResults() methods implemented.
	protected void showResults() {
		if (this.queryResult instanceof ReadQueryResult) {
			showQueryOutput((ReadQueryResult) this.queryResult);
		} else if (this.queryResult instanceof WriteQueryResult) {
			showQueryOutput((WriteQueryResult) this.queryResult);
		}
	}

	public boolean validateQuery() {
		// TODO Validate SQL queries?
		return true;
	}

	protected void showQueryOutput(final ReadQueryResult result) {
		System.out.println(TabularLayoutHelper.print(
				result.getHeadersAndData(), MAX_WIDTH));
		System.out.println("Displaying " + result.getNumOfRowsReturned()
				+ " rows");
	}

	protected void showQueryOutput(final WriteQueryResult result) {
		System.out.println("Modified " + result.getNumOfRowsModified()
				+ " rows");
	}
}